<?php

namespace app\common\service;

use app\common\model\NotifyModel;
use app\common\RootService;
use app\common\model\WalletModel;
use app\common\model\MoneyCashModel;
use redis\TaskHash;

class PayService extends RootService
{
    /**
     * 支付测试钱包账号
     * @var array
     */
    private $payAccount = [
        '341895187', // 币安账号
        '0973462850', // momo账号
    ];

    /**
     * 币安支付
     * @var string[]
     */
    private $binancePay = [
        'transfer' => '/transfer', // 转账接口
        'orderQuery' => '/orderQuery', // 订单查询接口
    ];

    /**
     * momo钱包配置
     * @var string[]
     */
    private $momoPay = [
        'apiUrl' => 'https://buncha.info/cashout/v2', // api请求地址
        'accessKey' => 'd2667ba2b94399c39f8ae167c7ef7443', // 访问秘钥
        'secretKey' => 'e619e3e0e988d1d90370f2f555717309' // 加密秘钥
    ];

    /**
     * 支付
     * @param int $cashId
     * @return array|void
     * @throws \app\common\RootException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function cashPay(int $cashId)
    {
        // 提现失败
        if (!$cashInfo = MoneyCashModel::where(['id' => $cashId, 'state' => 1])->find()) {
            $this->errorException(lang('invalid operation'));
        }
        // 更新状态系统操作中
        $cashInfo->state = MONEY_RECORD_STATE_SUCCESS;
        $cashInfo->save();
        // 切换支付方式
        return empty($cashInfo['type']) ? $this->momoPay($cashInfo) : $this->binanceTransfer($cashInfo);
    }

    /**
     * Momo 支付
     * @param MoneyCashModel $cashInfo
     * @return array
     * @throws \app\common\RootException
     */
    protected function momoPay(MoneyCashModel $cashInfo)
    {
        $this->inwardAccount($cashInfo['account']) && $cashInfo['receipt'] = 300; // 测试支付金额
        // 请求参数
        $requestData = ['type' => 'momo', 'receiver' => $cashInfo['account'], 'message' => 'transfer',
            'ref_id' => $this->refSuffix() . $cashInfo['id'], 'amount' => $cashInfo['receipt']];
        // header签名
        $headSign = $this->hmacSha256Digest(json_encode($requestData));
        $headerData = ['X-Access-Key' => $this->momoPay['accessKey'], 'X-Signature' => $headSign];
        // 发送请求
        httpPostJson($this->momoPay['apiUrl'], $requestData, $headerData);
        return ['msg' => '提交成功'];
    }

    /**
     * 币安转账
     * @param MoneyCashModel $cashInfo
     * @return array
     * @throws \app\common\RootException
     */
    protected function binanceTransfer(MoneyCashModel $cashInfo)
    {
        $this->inwardAccount($cashInfo['account']) && $cashInfo['receipt'] = 1; // 测试转账金额
        // 接口地址
        $apiUrl = config('rule.binanceApi') . $this->binancePay['transfer'];
        // 请求参数
        $postData = ['cashId' => $cashInfo['id'], 'amount' => $cashInfo['receipt'], 'account' => $cashInfo['account']];
        // 发送请求
        httpSend($apiUrl, $postData, 'POST');
        return ['msg' => '提交成功'];
    }

    /**
     * 提现失败
     * @param int $cashId
     * @param array $notify 通知内容
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function cashFailed(int $cashId, string $notify = '')
    {
        $cashModel = new MoneyCashModel();
        // 数据处理
        if ($cashInfo = $cashModel->where(['id' => $cashId])->find()) {
            try {
                $cashModel->startTrans();
                // 变更提现状态（失败）
                $cashInfo->state = MONEY_RECORD_STATE_FIELD;
                $cashInfo->save();
                // 保存通知
                if (!empty($notify)) {
                    $notifyData = [$notify];
                    NotifyModel::create(['cash_id' => $cashId, 'notify' => json_encode($notifyData)]);
                }
                // 将提现金额退回到余额账户
                $recordData = ['memberId' => $cashInfo['member_id'], 'currency' => CURRENCY_COIN, 'type' => MONEY_INCOME,
                    'state' => MONEY_RECORD_STATE_COMPLETE, 'method' => MONEY_RECORD_METHOD_REFUND,
                    'amount' => $cashInfo['amount'], 'write_date' => date('Y-m-d')];
                moneyRecordAdd($recordData);
                // 将钻石退回余额账户
                if (!empty($cashInfo['diamond'])) {
                    $recordData['currency'] = CURRENCY_DIAMOND;
                    $recordData['amount'] = $cashInfo['diamond'];
                    moneyRecordAdd($recordData);
                }
                // 修改提现账号状态(失败)
                if (!$cashModel->where(['account' => $cashInfo['account'], 'state' => MONEY_RECORD_STATE_COMPLETE])->count()) {
                    WalletModel::where(['account' => $cashInfo['account'], 'member_id' => $cashInfo['member_id']])->update(['state' => 1]);
                }
                // 提现失败通知用户
                $cashData = $this->cashData($cashInfo['member_id']);
                $cashData['show'] = 2;// 由于系统原因，您有一笔提现被退回
                (new TaskHash())->taskHash($cashInfo['member_id'], 'cash', $cashData);
                $cashModel->commit();
            } catch (\Exception $e) {
                $cashModel->rollback();
                $e;
            }
        }
    }

    /**
     * 提现数据
     * @return array|int|mixed
     */
    protected function cashData(int $memberId)
    {
        // 读取缓存
        if (!$cashData = (new TaskHash())->taskHash($memberId, 'cash')) {
            $quantity = MoneyCashModel::where(['member_id' => $memberId, 'state' => 3])->count();
            $cashData = ['qty' => $quantity, 'date' => date('Y-m-d'), 'receive' => 0];
        }
        // 提现失败提示
        isset($cashData['show']) || $cashData['show'] = 0;
        isset($cashData['total']) || $cashData['total'] = 0;
        return $cashData;
    }

    /**
     * 签名算法
     * @param $encryptionData
     * @return string
     */
    protected function hmacSha256Digest(string $encryptionData)
    {
        return base64_encode(hash_hmac('sha256', $encryptionData, $this->momoPay['secretKey'], true));
    }

    /**
     * 内部测试账号
     */
    protected function inwardAccount(string $account)
    {
        return $this->refSuffix() == 'dev_' || in_array($account, $this->payAccount);
    }

    /**
     * 支付前缀
     * @return string
     */
    protected function refSuffix()
    {
        $suffix = substr(request()->header('host'), 0, 3);
        return in_array($suffix, ['dev', 'soc']) ? 'dev_' : 'YL_';
    }

}